#ifndef SLICEUTILS_HPP
#define SLICEUTILS_HPP

#include <Eigen/Core>

#include "slice.hpp"
#include "sliceiterator.hpp"

using namespace Eigen;

namespace SliceUtils {
  //invert incoming slice values
  void invert(unsigned char &value);

  //parameters defining a sphere
  typedef struct SphereParam {
    Vector3d centre;
    double radius;
  } SphereParam;

  //pass src slice through spherical mask and store result in dest
  void sphereMask(unsigned char &src,unsigned char &dest,const Vector3i &index,void *param);

  //sum up values in slice
  void sum(unsigned char &value,void *param);

  //parameters for calculating centre of gravity
  typedef struct CoGParam {
    Vector3i accumulator;
    int num;
  } CoGParam;

  //calculate centre of gravity
  void cog(unsigned char &value,const Vector3i &index,void *param);

  //connected components parameters
  typedef struct LabelParam {
    int num;
    int label;
    QList<Vector3i> indices;
    QList<Vector3i> offsets;
    LabelParam() : num(0),label(1) {
      offsets << Vector3i(-1,0,0) << Vector3i(1,0,0) << Vector3i(0,-1,0)
        << Vector3i(0,1,0) << Vector3i(0,0,-1) << Vector3i(0,0,1);
    };
  } LabelParam;

  //label connected components
  void label(Slice &input,Slice &labelled,void *param);

  //bounding box parameters
  typedef struct BoundingBoxParam {
    Vector3i min;
    Vector3i max;
    unsigned char label;
  } BoundingBoxParam;

  //find bounding box of object voxels
  void boundingBox(unsigned char &value,const Vector3i &index,void *param);

  //grow region to include object voxels in 26-connected neighbourhood
  void grow(Slice &region,Slice &grown,Slice &object);

  //unset voxels inside mask
  void unset(unsigned char &value,unsigned char &mask);

  typedef struct FilterParam {
    unsigned char srcValue;
    unsigned char destValue;
  } FilterParam;

  //copy voxels from src to dest with filter on input and output values
  void filter(unsigned char &src,unsigned char &dest,void *param);

  typedef struct MaxDistanceParam {
    double distance;
    Vector3d point;
    MaxDistanceParam() : distance(0.0) {}
  } MaxDistanceParam;

  //calculate max distance from point to any voxel
  void maxDistanceToPoint(unsigned char &value,const Vector3i &index,void *param);
}

#endif
